/*-------------------------------------------------------------------------
 *
 * pg_db_cursor.h
 *
 *
 *   DESCRIPTION
 *		Postgres Cursor Database Class:
 *		   Query Postgres backend using a cursor
 *
 *   NOTES
 *      Currently under construction.
 *
 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 *  $Id: panda_db_cursor.h,v 1.1.1.1 2002/12/04 12:54:52 lg Exp $
 *
 *-------------------------------------------------------------------------
 */

#ifndef PG_DB_CURSOR_H
#define PG_DB_CURSOR_H

#include "libpq++/pgtransdb.h"
#include <string>
#include <vector>
#include <iosfwd>
#include <byteswap.h>

// ****************************************************************
//
// t_pg_cursor - a class for querying databases using a cursor
//
// ****************************************************************
// This is the database access class that declares a cursor and
// manipulates data through it.  The interface will introduce some
// ease of use through the methods that will allow cursor specific
// operations, like fetch, forward, etc.

class t_pg_cursor : public PgDatabase {

// helper classes
		template <class T, class U>
		struct t_pg_getvalue
		{	static T run(unsigned row, unsigned col, PGresult* pgResult)
			{return *reinterpret_cast<const T*>(PQgetvalue(pgResult, row, col));}};

		template <typename T, typename U>
		struct t_pg_getvalue<T, U[2]>
		{   static T run(unsigned row, unsigned col, PGresult* pgResult)
			{
				return T	(	bswap_32(*reinterpret_cast<const unsigned*>(
												PQgetvalue(pgResult, row, col)))
							);
			}
		};

		template <typename T, typename U>
		struct t_pg_getvalue<T,  U[4]>
		{   static T run(unsigned row, unsigned col, PGresult* pgResult)
			{
				union
				{
					T			f;
					unsigned	i;
				}			swap;

				swap.i = bswap_32(*reinterpret_cast<const unsigned*>(
												PQgetvalue(pgResult, row, col)));
				return swap.f;
			}
		};


		template <typename T, typename U>
		struct t_pg_getvalue<T,  U[8]>
		{   static T run(unsigned row, unsigned col, PGresult* pgResult)
			{
				union
				{
					T			f;
					unsigned	i[2];
				}			swap;

				const unsigned* pi =reinterpret_cast<const unsigned*>(
														PQgetvalue(pgResult, row, col));
				swap.i[0] = bswap_32(pi[1]);
				swap.i[1] = bswap_32(pi[0]);
				return swap.f;
			}
		};
public:

	template <typename T>
	inline T getvalue(unsigned row, unsigned col) const
	{
		return t_pg_getvalue<T, char[sizeof(T)]>::run(row, col, pgResult);
	}

	const char* getvalue(unsigned row, unsigned col) const
	{
		return PQgetvalue(pgResult, row, col);
	}
	PGresult* getresult(){return pgResult;}


	explicit t_pg_cursor(const char* conninfo, const char* cursor);	// use reasonable & environment defaults
	explicit t_pg_cursor(const std::string& conninfo, const std::string& cursor);

	// connect to the database with given environment and database name
	//  t_pg_cursor(const PgConnection&, const char* cursor);
	~t_pg_cursor();	// close connection and clean up

	// Commands associated with cursor interface
	int Declare(std::string query, bool binary=false);	// Declare a cursor with given name
	int Fetch(const char* dir = "FORWARD");		// Fetch ALL tuples in given direction
	int Fetch(unsigned num, const char* dir = "FORWARD");	// Fetch specified amount of tuples
	int Close();	// Close the cursor

	// Accessors to the cursor name
	const std::string& Cursor() const { return pgCursor_name; }
	// TODO: Setter has same name as getter--ouch!
	// OBSOLESCENT
	void Cursor(std::string cursor) { pgCursor_name = cursor; }

	using PgDatabase::PutLine;
	void PutLine(const std::string& str) {PutLine(str.c_str());}
	bool	Commit();
	bool	Rollback();
	bool	BeginTransaction();
	bool InTransaction() const {return !pgCommitted;}
	bool table_exists(const std::string& table_space, const std::string& table,
						std::ostream& CERR);
	// 		returns true if the SQL table already exists
	protected:
	int Fetch(std::string num, std::string dir);

protected:
	std::string		pgCursor_name;
	bool			pgCursor_open;
	bool			pgCommitted;

	protected:

	private:
	// We don't support copying of t_pg_cursor objects,
	// so make copy constructor and assignment op private.
	t_pg_cursor(const t_pg_cursor&);
	t_pg_cursor& operator= (const t_pg_cursor&);
}; // End t_pg_cursor Class Declaration

bool pg_print_sql_err(  const std::string& description,
						t_pg_cursor& pg_db,
						const std::string& sql_str,
						std::ostream& CERR);


struct t_lock_table
{
	t_pg_cursor& pg_db;
	t_lock_table(t_pg_cursor& pg_db, const std::string& name);
	~t_lock_table();
	void rollback();
private:
	bool in_transaction;
};

struct t_transaction
{
	t_pg_cursor& pg_db;
	t_transaction(t_pg_cursor& pg_db);
	~t_transaction();
	void rollback();
private:
	bool rolledback;
	bool in_transaction;
};


#endif	// PG_DB_CURSOR_H

